/* Orbas:
 *     A open source CORBA Specification implementation from Huihoo.
 *
 * Copyright 2002-2003 Huihoo.org, Inc. All Right Reserved.
 *
 * This software is licensed under LGPL license.
 * See terms of license at gnu.org.
 *
 * For more information, visit:
 *
 * http://www.huihoo.org/orbas
 */



package org.huihoo.orbas.orb.ior;

/**
 * <p>Description: </p>
 * IOR parser.
 * <p>Copyright (c) 2002,2003</p>
 * <p>Company: <a href="http://www.huihoo.org/">huihoo.org</a></p>
 * @author <a href="http://www.huihoo.org/~mep">mep(mep@huihoo.com)</a>
 * @see <a href="http://www.huihoo.org/orbas">http://www.huihoo.org/orbas</a>
 * @version 1.0
 */


import com.cognition.util.StringTokenizer;
import org.omg.IOP.IOR;
import org.omg.IOP.TaggedProfile;
import org.omg.IOP.TaggedProfileHelper;
import org.huihoo.orbas.orb.types.ObjectImpl;
import org.huihoo.orbas.orb.types.ObjRefDelegate;
import org.huihoo.orbas.orb.cdr.*;
import org.omg.CORBA.ORB;
import org.huihoo.orbas.orb.protocols.*;

public class IorParser {
    
    private org.omg.CORBA.ORB orb;
    private TargetAddress target;
    private TaggedProfile[] profiles;
    private String typeId;
    private String s;
    private byte[] ior;
    private byte[] objectKey;
    private org.omg.CORBA.Object obj;
    private int version = 0;

    public IorParser() {
        orb = null;
    }

    public IorParser(org.omg.CORBA.ORB orb, byte[] ior) {
        this.ior = ior;
        this.orb = orb;
        
    }
    
    public IorParser(org.omg.CORBA.ORB orb, CDRInputStream in){
        this.orb = orb;
        this.obj = parseObject(in);
        
    }

    public IorParser(org.omg.CORBA.ORB orb, String s) {
        this.orb = orb;
        this.s = s;
        this.obj = string2Object(s);
    }

    public IorParser(org.omg.CORBA.ORB orb, TaggedProfile[] profiles, String typeId) {
        this.orb = orb;
        this.profiles = profiles;
        this.typeId = typeId;

    }
	
	protected org.omg.CORBA.Object parseObject(CDRInputStream in){
		byte byteOrder = in.read_octet();
        if (byteOrder == 1)
            in.setLittleEndian(true);
        typeId = in.read_string();
        parseTaggedProfiles(in);
        ObjRefDelegate delegate = new ObjRefDelegate(this.orb, this);
        ObjectImpl objectImpl = new ObjectImpl();
        objectImpl._set_delegate(delegate);
        return objectImpl;
	}
	
    protected org.omg.CORBA.Object string2Object(String s) {
        if (s == null || s.length() == 0)
            return null;
        
        StringTokenizer tok = new StringTokenizer(s, ":");
        tok.nextToken();
        String iorContent = tok.nextToken();
        CDRInputStream in = new CDRInputStream(orb, string2Cdr(iorContent));
        
        byte byteOrder = in.read_octet();
        if (byteOrder == 1) {
            in.setLittleEndian(true);
        }
        
        typeId = in.read_string();
        parseTaggedProfiles(in);
        ObjRefDelegate delegate = new ObjRefDelegate(this.orb, this);
        ObjectImpl objectImpl = new ObjectImpl();
        objectImpl._set_delegate(delegate);
        return objectImpl;
    }

    protected void parseTaggedProfiles(CDRInputStream in) {
        int nProfiles = in.read_long();
        profiles = new TaggedProfile[nProfiles];
        
        for (int i = 0; i < nProfiles; i++) {
            
            profiles[i] = parseSingleProfile(in);
            
            //read tag from config file to select supported protocols
            if( profiles[i].tag == org.omg.IOP.TAG_INTERNET_IOP.value ) {
                //IIOP profile,select support ProfileExactor

                if (orb instanceof org.huihoo.orbas.orb.ORB){
                    org.huihoo.orbas.orb.ORB huiOrb =
                            (org.huihoo.orbas.orb.ORB)orb;
                    ProfileRegistry profiledealers = huiOrb.getProfileRegistry();
                    ProfileExtractor extractor = profiledealers.getProfileExtractor(org.omg.IOP.TAG_INTERNET_IOP.value);

                    if( extractor == null ) {
                        //we cannot deal with this protocols
                        System.out.println("Error : Transport protocol NOT supported.");
                    }
                    CDRInputStream profileBodyIn = new CDRInputStream(profiles[i].profile_data);

                    byte byteOrder = profileBodyIn.read_octet();
                    if (byteOrder == 1) {
                        profileBodyIn.setLittleEndian(true);
                    }
                    else {
                        profileBodyIn.setLittleEndian(false);
                    }

                    extractor.setInputStream(profileBodyIn);
                    extractor.parse();
                    target = extractor.getTargetAddress();
                    objectKey = extractor.getObjectKey();
                    version = extractor.getVersion();
                }
                
            }
            else if( profiles[i].tag == org.omg.IOP.TAG_MULTIPLE_COMPONENTS.value ) {
                if (orb instanceof org.huihoo.orbas.orb.ORB){
                    org.huihoo.orbas.orb.ORB huiOrb =
                            (org.huihoo.orbas.orb.ORB)orb;

                    //do the same thing?
                    ProfileRegistry profiledealers = huiOrb.getProfileRegistry();
                    ProfileExtractor extractor = profiledealers.getProfileExtractor(org.omg.IOP.TAG_MULTIPLE_COMPONENTS.value);

                    if( extractor == null ) {
                        //we cannot deal with this protocols
                        System.out.println("Error : Transport protocol NOT supported.");
                    }

                    extractor.parse();
                    target = extractor.getTargetAddress();
                    objectKey = extractor.getObjectKey();

                }
            }
            
        }
        
    }

    protected TaggedProfile parseSingleProfile(CDRInputStream in) {
        TaggedProfile profile;
        
        profile = TaggedProfileHelper.read(in);
        
        return profile;

    }
    
    public byte[] writeTaggedProfiles() {
        CDROutputStream out = new CDROutputStream(orb);
        
        out.write_boolean(false);
        out.write_string(typeId);
        
        out.write_long(profiles.length);
        for ( int i = 0;i<profiles.length;i++ ) {
            TaggedProfile p = profiles[i];
            TaggedProfileHelper.write(out,p);

        }
        
        ior = new byte[out.getLength() + 1];
        System.arraycopy(out.getBuffer(), 0, ior, 0, out.getLength());
        
        return ior;
    }

    public String object2String() {
        
        return cdr2String(ior, ior.length);
    }

    protected String cdr2String(byte[] b, int bLen) {
        int resultLen = 4 + 2 * b.length;
        StringBuffer result = new StringBuffer(resultLen);
        result.append('I');
        result.append('O');
        result.append('R');
        result.append(':');
        for (int j = 0; j < bLen; j++) {
            byte c = b[j];
            result.append(int2Hex((c >> 4) & 0xF));
            result.append(int2Hex(c & 0xF));
        }
        return result.toString();
    }

    protected char int2Hex(int i) {
        switch (i) {
            case 0:
                return '0';
            case 1:
                return '1';
            case 2:
                return '2';
            case 3:
                return '3';
            case 4:
                return '4';
            case 5:
                return '5';
            case 6:
                return '6';
            case 7:
                return '7';
            case 8:
                return '8';
            case 9:
                return '9';
            case 10:
                return 'A';
            case 11:
                return 'B';
            case 12:
                return 'C';
            case 13:
                return 'D';
            case 14:
                return 'E';
            case 15:
                return 'F';
            default:
                //?
                return '0';
        }
    }

    protected byte[] string2Cdr(String s) {
        int src = 0;
        int dst = 0;
        int sLen = s.length();
        int resultLen = sLen  / 2;
        byte[] result = new byte[resultLen];
        while (src < sLen) {
            char first = s.charAt(src++);
            char second = s.charAt(src++);
            byte combined = (byte)(((hex2Int(first) & 0xF) << 4) | (hex2Int(second) & 0xF));
            result[dst++] = combined;
        }
        return result;
    }

    protected int hex2Int(char c) {
        switch (c) {
            case '0':
                return 0;
            case '1':
                return 1;
            case '2':
                return 2;
            case '3':
                return 3;
            case '4':
                return 4;
            case '5':
                return 5;
            case '6':
                return 6;
            case '7':
                return 7;
            case '8':
                return 8;
            case '9':
                return 9;
            case 'A':
            case 'a':
                return 10;
            case 'B':
            case 'b':
                return 11;
            case 'C':
            case 'c':
                return 12;
            case 'D':
            case 'd':
                return 13;
            case 'E':
            case 'e':
                return 14;
            case 'F':
            case 'f':
                return 15;
            default:
                //?
                return 0;
        }
    }

    public String getTypeId() {
        return typeId;
    }

    public TaggedProfile[] getProfiles() {
        return profiles;
    }

    public org.omg.CORBA.Object getObject() {
        if( obj == null ) {
            ObjRefDelegate delegate = new ObjRefDelegate(this.orb, this);
            ObjectImpl objectImpl = new ObjectImpl();
            objectImpl._set_delegate(delegate);
            return objectImpl;
        }
        
        return obj;
    }

    public byte[] getBytes() {
        if( ior == null ) {
            writeTaggedProfiles();
        }
        return ior;
    }

    public String toString() {
        if( ior == null ) {
            writeTaggedProfiles();
        }
        if( s == null ) {
            s = object2String();
        }
        return s;
    }

    public boolean isA(String Id) {
        return (typeId.equals(Id));
    }
    
    public byte[] getObjectKey() {
        if( objectKey == null ){
            
        }
        
        return objectKey;
    }
    
   	public TargetAddress getAddress() {
        return target;
    }
    
    public int getVersion() {
    	return version;
    }

}
